home *** CD-ROM | disk | FTP | other *** search
/ Alles Voor Internet / Tout Pour Internet / alles voor internet.iso / MacInternet™ / Telnet / Terminal 2.2 / Project / Sources / Macros.c < prev    next >
Text File  |  1992-01-17  |  8KB  |  394 lines

  1. /*
  2.     Terminal 2.2
  3.     "Macros.c"
  4. */
  5.  
  6. #ifdef THINK_C
  7. #include "MacHeaders"
  8. #endif
  9. #ifdef applec
  10. #pragma load ":(Objects):MacHeadersMPW"
  11. #pragma segment Main2
  12. #endif
  13.  
  14. #include "Strings.h"
  15. #include "Utilities.h"
  16. #include "MySF.h"
  17. #include "Text.h"
  18. #include "Main.h"
  19. #include "Document.h"
  20. #include "Port.h"
  21. #include "Macros.h"
  22.  
  23. #define MAXMACROS    10    /* Maximal number of macros */
  24. #define MAXNAME        30    /* Maximal size of macro name */
  25. #define MACRO_EOF    (-1)
  26. #define MACRO_NAME    (-2)
  27.  
  28. typedef struct {
  29.     union {
  30.         long offset;    /* Relative offset to macro text */
  31.         Byte *ptr;
  32.     } x;
  33.     long length;        /* Length of macro text */
  34. } MINFO;
  35.  
  36. /*
  37.     The global variable "MacrosText" is a handle to a structure in
  38.     memory described as:
  39.  
  40.     struct {
  41.         MINFO info[MAXMACROS];
  42.         Byte data[...];
  43.     }
  44.  
  45.     The handle is locked all the time. "info.offset" is the relative
  46.     offset of the macros text, relative to the beginning of the
  47.     structure. "info.length" is the length, in bytes, of the macro text.
  48.     If a macro is not used its offset and length are set to zero.
  49.  
  50.     A complete set of macros (up to 10 macros) is stored in a macro file
  51.     (TEXT file with ".m" suffix) in the following format:
  52.  
  53.     \M<macro name>
  54.     <macro text>
  55.     \M<macro name>
  56.     <macro text>
  57.     ...
  58.  
  59.     The macro name must start with "\M" or "\m" and is terminated by the
  60.     next return character. The macro text follows the macro name and is
  61.     terminated by the beginning of the next macro name or by the end of
  62.     the file. To include control characters into the macro text use a
  63.     backslash followed by the character (upper and lower case are
  64.     identical), e.g. control-C becomes "\C". You cannot use "\M" because
  65.     this starts a new macro name, simply use the return character
  66.     (control-M is the same as carriage return). To use the backslash
  67.     itself use "\\". The last return character, the one just before the
  68.     next macro name is not included in the macro text.
  69. */
  70.  
  71. /* ----- Static data --------------------------------------------------- */
  72.  
  73. static long Textsize;
  74. static Byte *Text;
  75.  
  76. /* ----- Get next character -------------------------------------------- */
  77.  
  78. static short NextChar(void)
  79. {
  80.     register short b;
  81.  
  82.     if (Textsize <= 0)
  83.         return MACRO_EOF;
  84.     --Textsize;
  85.     if ((b = *Text++) != '\\')
  86.         return b;
  87.     if (Textsize <= 0)
  88.         return MACRO_EOF;
  89.     --Textsize;
  90.     b = *Text++;
  91.     if (b >= 'a' && b <= 'z')
  92.         b -= 'a' - 'A';
  93.     switch (b) {
  94.         case 'M':
  95.             return MACRO_NAME;
  96.         case '\\':
  97.             return '\\';
  98.     }
  99.     return b - '@';
  100. }
  101.  
  102. /* ----- Parse macros file --------------------------------------------- */
  103.  
  104. enum {
  105.     WAITNAME,
  106.     WAITEON,
  107.     WAITEOT
  108. };
  109.     
  110. static long ParseMacros(
  111.     Byte *text,
  112.     long size,
  113.     register Byte *macros)        /* If 0 only calculate length */
  114. {
  115.     register MINFO *p;
  116.     register Byte *q;
  117.     Byte name[MAXNAME + 1];
  118.     register short state;
  119.     register short item;
  120.     register short c;
  121.     MenuHandle mh;
  122.  
  123.     Text = text;
  124.     Textsize = size;
  125.     p = (MINFO *)macros;
  126.     if (macros) {
  127.         if (!(mh = GetMenu(MACRO)))
  128.             return 0;
  129.         for (item = 0; item < MAXMACROS; ++item) {
  130.             SetItem(mh, item + DOMACRO1, "\p ");
  131.             DisableItem(mh, item + DOMACRO1);
  132.             p[item].x.offset = 0;
  133.             p[item].length = 0;
  134.         }
  135.     }
  136.     q = (Byte *)(p + MAXMACROS) - 1;
  137.     state = WAITNAME;
  138.     item = 0;
  139.  
  140.     while ((c = NextChar()) != MACRO_EOF) {
  141.         switch (state) {
  142.             case WAITNAME:        /* Waiting for beginning of name */
  143.                 if (c == MACRO_NAME) {
  144.                     if (macros)
  145.                         *name = 0;    /* Prepare to make pascal string */
  146.                     state = WAITEON;
  147.                 }
  148.                 break;
  149.             case WAITEON:        /* Waiting for end of name */
  150.                 switch (c) {
  151.                     case '\015':
  152.                         if (macros && item < MAXMACROS) {
  153.                             SetItem(mh, item + DOMACRO1, name);
  154.                             EnableItem(mh, item + DOMACRO1);
  155.                             p[item].x.ptr = q + 1;
  156.                         }
  157.                         state = WAITEOT;
  158.                         break;
  159.                     default:
  160.                         if (macros && *name < MAXNAME) {
  161.                             ++(*name);
  162.                             name[*name] = c;
  163.                         }
  164.                 }
  165.                 break;
  166.             case WAITEOT:        /* Waiting for end of macro text */
  167.                 switch (c) {
  168.                     case MACRO_NAME:
  169.                         if (macros && item < MAXMACROS) {
  170.                             *name = 0;    /* Prepare to make pascal string */
  171.                             if (q > p[item].x.ptr)
  172.                                 p[item].length = q - p[item].x.ptr;
  173.                             else {
  174.                                 p[item].length = 0;
  175.                                 p[item].x.offset = 0;
  176.                                 DisableItem(mh, item + DOMACRO1);
  177.                             }
  178.                             ++item;
  179.                         }
  180.                         state = WAITEON;
  181.                         break;
  182.                     default:
  183.                         ++q;
  184.                         if (macros && item < MAXMACROS)
  185.                             *q = c;
  186.                         break;
  187.                 }
  188.         }
  189.     }
  190.  
  191.     /* Last macro text */
  192.  
  193.     if (state == WAITEOT) {
  194.         if (macros && item < MAXMACROS) {
  195.             if (q > p[item].x.ptr)
  196.                 p[item].length = q - p[item].x.ptr;
  197.             else {
  198.                 p[item].length = 0;
  199.                 p[item].x.offset = 0;
  200.                 DisableItem(mh, item + DOMACRO1);
  201.             }
  202.         }
  203.     }
  204.  
  205.     /* Make relative offsets */
  206.  
  207.     if (macros)
  208.         for (item = 0; item < MAXMACROS; ++item)
  209.             if (p[item].x.offset)
  210.                 p[item].x.offset -= (long)macros;
  211.  
  212.     return q - macros + 1;    /* Add one spare byte at the end */
  213. }
  214.  
  215. /* ----- Get macro name ------------------------------------------------ */
  216.  
  217. void NameMacro(
  218.     register short item,
  219.     register Byte *name)
  220. {
  221.     register MenuHandle mh;
  222.  
  223.     *name = 0;
  224.     if (!(MacrosText && (mh = GetMenu(MACRO)) &&
  225.             item >= DOMACRO1 && item < DOMACRO1 + MAXMACROS))
  226.         return;
  227.     GetItem(mh, item, name);
  228.     return;
  229. }
  230.  
  231. /* ----- Execute macro (or cancel macro) ------------------------------- */
  232.  
  233. short DoMacro(
  234.     register short item,
  235.     Boolean display)
  236. {
  237.     register Byte *buf;
  238.     register long size;
  239.     short err;
  240.  
  241.     {
  242.         register MINFO *p;
  243.  
  244.         item -= DOMACRO1;
  245.         if (item < 0 || item >= MAXMACROS)
  246.             return FINE;
  247.         p = (MINFO *)(*MacrosText);
  248.         p += item;
  249.         if (!p->x.offset || !p->x.offset)
  250.             return FINE;
  251.         buf = (Byte *)(*MacrosText) + p->x.offset;
  252.         size = p->length;
  253.     }
  254.  
  255.     if (display) {
  256.         NewCharacters(buf, size, FALSE);
  257.         return FINE;
  258.     }
  259.  
  260.     if (Transfer)
  261.         return FINE;
  262.     if (Sending) {        /* Cancel by reselecting menu item */
  263.         SerialAbort();
  264.         Sending = FALSE;
  265.         return FINE;
  266.     }
  267.  
  268.     item += DOMACRO1;
  269.     Sending = TRUE;
  270.     Control_X = FALSE;
  271.     SetItemStyle(GetMenu(MACRO), item, ACTIVE);
  272.     /* SerialHandshake(Settings.handshake); */
  273.     do {
  274.         register Byte *buffer;
  275.         register long count;
  276.         Byte save;
  277.  
  278.         buffer = buf;
  279.         if (size && Settings.chardelay) {
  280.             ++buf;
  281.             --size;
  282.         } else {
  283.             while (size && *buf != '\015') {
  284.                 ++buf;
  285.                 --size;
  286.             }
  287.             if (size) {
  288.                 ++buf;
  289.                 --size;
  290.             }
  291.         }
  292.         count = buf - buffer;
  293.         if (!count)
  294.             break;
  295.         while (Busy)
  296.             ;
  297.         save = *buf;    /* May be replaced by LF */
  298.         if (buffer[count-1] == '\015') {
  299.             if (Settings.autoLF)
  300.                 buffer[count++] = '\012';
  301.             SerialSend(buffer, count, &Busy);
  302.             if (Settings.localEcho)
  303.                 NewCharacters(buffer, count, FALSE);
  304.             if (Settings.linedelay || Settings.prompt[0])
  305.                 Loop(Settings.linedelay,(Byte *)Settings.prompt,1);
  306.             else
  307.                 CheckEvents();
  308.         } else {
  309.             SerialSend(buffer, count, &Busy);
  310.             if (Settings.localEcho)
  311.                 NewCharacters(buffer, count, FALSE);
  312.             if (Settings.chardelay)
  313.                 Loop(Settings.chardelay, 0, 0);
  314.             else
  315.                 CheckEvents();
  316.         }
  317.         while (Busy)
  318.             ;
  319.         *buf = save;
  320.     } while (Sending);
  321.  
  322.     err = Sending ? FINE : (Control_X ? ABORT : CANCEL);
  323.     SetItemStyle(GetMenu(MACRO), item, 0);
  324.     Sending = FALSE;
  325.     Control_X = FALSE;
  326.     /* SerialHandshake(0); */
  327.     return err;
  328. }
  329.  
  330. /* ----- Load macros file ---------------------------------------------- */
  331.  
  332. short LoadMacros(
  333.     short volume,
  334.     long directory,
  335.     Byte *name)        /* If NIL use dialog to select */
  336. {
  337.     register Handle h;
  338.     short ref;
  339.     short err;
  340.     SFReply sfr;
  341.     long size;
  342.  
  343.     /* Get file name if not yet specified, open the file */
  344.  
  345.     if (name)
  346.         err = OpenFile(volume, directory, name, &ref);
  347.     else {
  348.         MySFGetFile(MyString(STR_G,G_MACRO), MyString(STR_G,G_MSUFFIX),
  349.             1, &TEXT, &sfr, 0);
  350.         RedrawDocument();
  351.         if (!sfr.good)
  352.             return noErr;
  353.         err = OpenFile(sfr.vRefNum, 0, (Byte *)sfr.fName, &ref);
  354.     }
  355.     if (err)
  356.         return err;
  357.  
  358.     /* Get rid of previous macros */
  359.  
  360.     if (MacrosText) {
  361.         DisposHandle(MacrosText);
  362.         MacrosText = 0;
  363.     }
  364.  
  365.     /* Read new macros into memory and close the file */
  366.  
  367.     GetEOF(ref, &size);
  368.     if (h = NewHandle(size)) {
  369.         HLock(h);
  370.         if (err = FSRead(ref, &size, *h))
  371.             DisposHandle(h);
  372.     } else
  373.         err = memFullErr;
  374.     FSClose(ref);
  375.     if (err)
  376.         return err;
  377.  
  378.     /* Parse the macros and save them */
  379.  
  380.     if (MacrosText = NewHandle(ParseMacros((Byte *)*h, size, 0))) {
  381.         HLock(MacrosText);
  382.         ParseMacros((Byte *)*h, size, (Byte *)*MacrosText);
  383.         HUnlock(MacrosText);
  384.         DisposHandle(h);
  385.         MoveHHi(MacrosText);
  386.         HLock(MacrosText);
  387.         err = noErr;
  388.     } else {
  389.         DisposHandle(h);
  390.         err = memFullErr;
  391.     }
  392.     return err;
  393. }
  394.